/**
 * WordGuessTournament class works as a driver for the play 
 * of the word games.
 * CSCE 155 Spring 2010
 * Assignment 2
 * @author Josh Branchaud
 * @version 1.0, 02/03/2010
 */

// import statements
import java.util.*;

public class WordGuessTournament
{

    // -------------------------------------------------------------------------
    // You may add more data members to the following to describe a 
	// WordGuessTournament.
    // -------------------------------------------------------------------------
    
    // private data members -- variables
    private Player playerOne;  // stores the information for player one
    private Player playerTwo;  // stores the information for player two

    // boolean that represents if the players want to keep playing more games
    private boolean keepPlaying;

    private String secretWord; // the secret word used for the games

    private int whoseFirst;
    
    // -------------------------------------------------------------------------
    // Here are the public and private methods that specify the game tournament.
    // First of all, player objects will provide some information for you, will
    // allow you to change its settings, and will also do quite a bit of other
    // things.  You may add new methods.
    // -------------------------------------------------------------------------
    
    /** Constructor
     *  initialize all private data members to appropriate values
     *  If you add more data members, you will have to initialize them here
     *  too.
     */
    public WordGuessTournament()
    {
        this.playerOne = new Player();
        this.playerTwo = new Player();
        this.keepPlaying = true;
        this.secretWord = "";
        this.whoseFirst = 1;
    }  // end constructor

    //--------------------------------------------------------------------------
    //Please Complete the playGame method below
    //This method will run the games for the players
    //--------------------------------------------------------------------------
    public void playGame()
    {
        int choice; // the game choice of the players

        String outcome = ""; // the outcome of a given game (win or lose)

        // First, obtain the player's choice of game to play.
        choice = this.obtainGameChoice();

        // Play appropriate game based on the player's input.
        if(choice == 1)
        {
            // play game 1
            WordGuessGameOne hangman = new WordGuessGameOne();
            outcome = hangman.playGameOne(this.secretWord, this.whoseFirst);

            // Post-game housekeeping, switch start player, update incorrect guesses
            this.switchWhoseFirst();

            if(this.whoseFirst == 1)
            {
                this.playerOne.setIncorrectGuesses(this.playerOne.getIncorrectGuesses() +
                        hangman.getIncorrectGuesses());
            }
            else if(this.whoseFirst == 2)
            {
                this.playerTwo.setIncorrectGuesses(this.playerTwo.getIncorrectGuesses() +
                        hangman.getIncorrectGuesses());
            }
            else
            {
                // do nothing, we have an issue.
            }
        }
        else if(choice == 2)
        {
            // play game 2
            WordGuessGameTwo wordjumble = new WordGuessGameTwo();
            outcome = wordjumble.playGameTwo(this.secretWord, this.whoseFirst);

            // Post-game housekeeping, switch start player, update time taken
            this.switchWhoseFirst();

            if(this.whoseFirst == 1)
            {
                this.playerOne.setGuessingTime(this.playerOne.getGuessingTime() +
                        wordjumble.getTime());
            }
            else if(this.whoseFirst == 2)
            {
                this.playerTwo.setGuessingTime(this.playerTwo.getGuessingTime() +
                        wordjumble.getTime());
            }
            else
            {
                // do nothing
            }
        }
        else
        {
            System.out.println("There was an error with your game choice.");
        }

        if(outcome.compareTo("win") == 0)
        {
            if(this.whoseFirst == 1)
            {
                this.playerOne.setGamesWon(this.playerOne.getGamesWon() + 1);
            }
            else if(this.whoseFirst == 2)
            {
                this.playerTwo.setGamesWon(this.playerTwo.getGamesWon() + 1);
            }
            else
            {
                // do nothing
            }
        }
        else
        {
            // do nothing
        }

    }//end of playGame
    
    /**
     * This method displays a welcome message to the user.
     */
    public void displayWelcome()
    {
        
        /* Display a brief welcome message about the program */
        System.out.println("****************************************************");
        System.out.println("*           Welcome to my Word Game World          *");
        System.out.println("*                By: Josh Branchaud                *");
        System.out.println("****************************************************");
        System.out.println("");
        
    }  // end displayWelcome
    
    /**
     * This method displays a goodbye message to the user.
     */
    public void displayGoodbye()  {
        
        /* Display a brief goodbye message from the system */
        System.out.println("");
        System.out.println("Thanks for playing!");
        
    }  // end displayGoodbye
    
    /**
     * This method obtains the information from the user.  It calls
     * readInteger() to obtain the game choice for play.  
     * Note that this method does not return anything at this point.
     * Yet to be implemented.
     * @param None
     * @return int
     */
    public int obtainGameChoice()
    {
        int response; // variable for the player's response.
        // 1.  Prompt the user to enter a game choice.
        // 2.  Call "readInteger()" to get the number.
        // 3.  Then store the integer.
        //
        System.out.println("Would you like to play Hangman or Word Jumble?");
        System.out.print("Enter 1 for Hangman or 2 for Word Jumble: ");
        
        response = this.readInteger();
        System.out.println("");

        // Check that there was valid input given, if not, then ask for new input.
        if(response != 1 && response != 2)
        {
            System.out.println("Invalid Option Selected.");
            this.obtainGameChoice();
        }

        return response;

    }  // end obtainGameChoice

    /**
     * This method prompts the user to play another game and processes the
     * response they give. If they give an invalid response, then they will be
     * prompted to enter a new response.
     */
    public void playAgain()
    {
        String response; // variable for the player's response.

        // Prompt the user to play another game.
        System.out.println("Would you like to play another game? (y/n)");
        response = this.readString();
        response = response.toUpperCase();

        // Determine if the player wants to play again based on response
        if(response.compareTo("Y") == 0 || response.compareTo("YES") == 0)
        {
            // Do nothing really.
            // Make sure that keepPlaying remains true.
            this.keepPlaying = true;
        }
        else if(response.compareTo("N") == 0 || response.compareTo("NO") == 0)
        {
            // Player doesn't want to continue playering, make it false
            this.keepPlaying = false;
        }
        else
        {
            // Any other input is invalid and the user will be prompted again.
            System.out.println("Invalid response!");
            this.playAgain();
        }
    }

    /**
     * This method obtains the information from the user.  It calls
     * readString() to obtain the player name.  
     * Note that this method does not return anything at this point.
     * Yet to be implemented.
     */
    public void obtainName()
    {
        String player1Name, player2Name;
        // 1.  Prompt the player to enter a name.
        // 2.  Call "readString()" to get the name.
        // 3.  Then store the name.
        //

        // Get the name for player1
        System.out.print("Please enter a name for player1: ");
        player1Name = this.readString();
        System.out.print("");

        // Get the name for player2
        System.out.print("Please enter a name for player2: ");
        player2Name = this.readString();
        System.out.print("");

        // Set the given names for player1 and player2
        this.playerOne.setName(player1Name);
        this.playerTwo.setName(player2Name);
        
    }  // end obtainName

    /**
     * obtainSecretWord prompts the player to enter a secret word to be used
     * for either game1 or game2. The secret word shouldn't contain any spaces
     * or special characters. The only characters allowed are [a-zA-Z]. Once the
     * secret word is entered, it should be converted to all uppercase.
     * @param None
     * @return void
     */
    public void obtainSecretWord()
    {
        String firstPlayerName = "";

        if(this.whoseFirst == 1)
        {
            firstPlayerName = this.playerOne.getName();
        }
        else
        {
            firstPlayerName = this.playerTwo.getName();
        }

        // Prompt the player to enter a secret word.
        System.out.println("To play Hangman and Word Jumble, you need a secret word.");
        System.out.println("The secret word can only contain A through Z, which means");
        System.out.println("that you can't use any spacing or special characters.");
        System.out.print(firstPlayerName + ", please enter your secret word: ");

        // Call readString() to get the secretWord from the user.
        this.secretWord = this.readString().toUpperCase();
        
    } // end obtainSecretWord

    /**
     * switchWhoseFirst will look at whatever the value of whoseFirst is and if
     * it is 1 then it will become 2, if it is 2 then it will become 1 and if it
     * is any other value, then it will become 1.
     * @param None
     * @return void
     */
    public void switchWhoseFirst()
    {
        if(this.whoseFirst == 1)
        {
            this.whoseFirst = 2;
        }
        else if(this.whoseFirst == 2)
        {
            this.whoseFirst = 1;
        }
        else
        {
            this.whoseFirst = 1;
        }
    }


    //*** Getter Methods for Private Variables ***//
    // Only the private variables that we need access to have methods.

    /**
     * getPlayerOne retrieves the player object represented by playerOne.
     * @param None
     * @return Player
     */
    public Player getPlayerOne()
    {
        return this.playerOne;
    }

    /**
     * getPlayerTwo retrieves the player object represented by playerTwo.
     * @param None
     * @return Player
     */
    public Player getPlayerTwo()
    {
        return this.playerTwo;
    }

    /**
     * getSecretWord retrieves the String object represented by secretWord.
     * @param None
     * @return String
     */
    public String getSecretWord()
    {
        return this.secretWord;
    }

    /**
     * getWhoseFirst retrieves the int object represented by whoseFirst.
     * @param None
     * @return int
     */
    public int getWhoseFirst()
    {
        return this.whoseFirst;
    }

    //*** end of Getter Methods ***//

    //*** Setter Methods for Private Variables ***//

    /**
     * setWhoseFirst sets this whoseFirst to the given int value.
     * @param newWhoseFirst
     * @return void
     */
    public void setWhoseFirst(int newWhoseFirst)
    {
        this.whoseFirst = newWhoseFirst;
    }

    /**
     * determineWinner compares the various statistics of the two players and
     * determines a winner. The winner is the one with the most wins, but if
     * they tie in wins, then the one with the least incorrect guesses and the
     * least amount of time used wins. However, in the unlikely event that they
     * also tie in both of those values, then there is a draw.
     * @param None
     * @return void
     */
    public void determineWinner()
    {
        if(this.playerOne.getGamesWon() > this.playerTwo.getGamesWon())
        {
            System.out.println(this.playerOne.getName() + " wins this set of games!");
        }
        else if(this.playerTwo.getGamesWon() > this.playerOne.getGamesWon())
        {
            System.out.println(this.playerTwo.getName() + " wins this set of games!");
        }
        else
        {
            // Multiple each players incorrectGuesses by their guessingTime
            // The person with the lower value is then the winner.
            long playerOnePoints = this.playerOne.getIncorrectGuesses()
                    * this.playerOne.getGuessingTime();
            long playerTwoPoints = this.playerTwo.getIncorrectGuesses()
                    * this.playerTwo.getGuessingTime();

            System.out.print("There was a tie, but ");

            if(playerOnePoints < playerTwoPoints)
            {
                System.out.println(this.playerOne.getName() + " had a better score.");
                System.out.println(this.playerOne.getName() + " wins this set of games!");
            }
            else if(playerOnePoints > playerTwoPoints)
            {
                System.out.println(this.playerTwo.getName() + " had a better score.");
                System.out.println(this.playerTwo.getName() + " wins this set of games!");
            }
            else
            {
                System.out.println("The players have tied. There is a draw!");
            }
        }
    }

    //*** end of Setter Methods ***//

    /**
     * This method reads in an integer and returns that integer to the
     * caller of this method.
     */
    private int readInteger()  {
        
        int temp = 0;
        Scanner scanner = new Scanner(System.in);
       
        try {
            temp = scanner.nextInt();
        }  catch (InputMismatchException ex) {
            System.out.println(ex);
        }
        
        return temp;
        
    }  // end readInteger
    
    /**
     * This method reads in a string and returns that string to the caller of
     * this method.
     */
    private String readString()  {
        
        String userInput = "";
        Scanner scanner = new Scanner(System.in);
        
        userInput = scanner.nextLine();
        
        return userInput;
        
    }  // end readString

    /**
     * This main method creates an object of the WordGameTournament class 
     * and runs the system. 
     *
	 * @param args
	 */
	public static void main(String[] args) {

		WordGuessTournament myTournament = new WordGuessTournament();
		myTournament.displayWelcome();
		
        // Ask the users for their names
        myTournament.obtainName();

        while(myTournament.keepPlaying)
        {
            // Ask the player for a secret word to use in game play
            myTournament.obtainSecretWord();

            // Ask the users which game they want to play
            myTournament.playGame();

            // Ask the player if they want to play again
            myTournament.playAgain();
        }

        // Call the method to determine the winner.
        myTournament.determineWinner();

        // Say goodbye
        myTournament.displayGoodbye();
	                                     
	}  // end main

} // end Class WordGuessTournament
